package com.project.srtp.secure.service.impl;

import com.project.srtp.secure.dto.req.*;
import com.project.srtp.secure.dto.resp.GetDecryptionSenderKeyRespDTO;
import com.project.srtp.secure.dto.resp.InitKeyRespDTO;
import com.project.srtp.secure.dto.resp.PreKeyBundleRespDTO;
import com.project.srtp.secure.common.biz.UserContextHolder;
import com.project.srtp.secure.dao.entity.IdentityKeyDO;
import com.project.srtp.secure.dao.entity.InitKeyDO;
import com.project.srtp.secure.dao.entity.PreKeyDO;
import com.project.srtp.secure.dao.entity.SignedPreKeyDO;
import com.project.srtp.secure.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 曹行阳
 * @version 0.1
 * @date 2025/6/15 17:47
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class KeyStoreServiceImpl implements KeyStoreService {

    private final SignedPreKeyService signedPreKeyService;
    private final PreKeyService preKeyService;
    private final IdentityKeyService identityKeyService;
    private final InitKeyService initKeyService;
    private final UserService userService;
    private final EncryptionSenderKeyService encryptionSenderKeyService;
    private final DecryptionSenderKeyService decryptionSenderKeyService;


    @Override
    public void storeInitKey(InitKeyReqDTO request) {
        String userId = request.getUserId();

        // 存储 IdentityKey
        identityKeyService.storeIdentityKey(request.getIdentityKey(), request.getUserId());

        // 存储 SignedPreKey
        signedPreKeyService.storeSignedPreKey(request.getSignedPreKey(), request.getUserId());

        // 存储 PreKeys（批量）
        preKeyService.storePreKeys(request.getPreKeys(), request.getUserId());


        // 存储 InitKey（摘要信息）
        InitKeyDO initKeyDO = InitKeyDO.builder().
                userId(userId).
                passwordHash(request.getPasswordHash()).
                passwordSalt(request.getPasswordSalt()).
                oneTimeId(request.getOneTimeId()).
                localId(request.getLocalId()).
                build();
        initKeyService.storeInitKey(initKeyDO);
    }

    @Override
    public InitKeyRespDTO fetchInitKeys() {
        Long id = UserContextHolder.getUserId();
        if (id == null) {
            throw new IllegalStateException("Id not found in context");
        }
        String userId = userService.getUserId(id);
        if (userId.isEmpty()) {
            throw new IllegalStateException("UserId not found in DB");
        }

        // 查询 IdentityKey
        IdentityKeyDO identityKeyDO = identityKeyService.selectIdentityKeyByUserId(userId);
        if (identityKeyDO == null) {
            throw new RuntimeException("IdentityKey not found for user " + userId);
        }

        // 查询 SignedPreKey
        SignedPreKeyDO signedPreKeyDO = signedPreKeyService.selectSignedPreKeyByUserId(userId);
        if (signedPreKeyDO == null) {
            throw new RuntimeException("SignedPreKey not found for user " + userId);
        }

        // 查询 PreKeys 列表
        List<PreKeyDO> preKeyDOS = preKeyService.selectPreKeysByUserId(userId);
        if (preKeyDOS == null) {
            preKeyDOS = Collections.emptyList();
        }

        // 查询 InitKey（密码哈希等）
        InitKeyDO initKeyDO = initKeyService.selectInitKeyByUserId(userId);
        if (initKeyDO == null) {
            throw new RuntimeException("InitKey not found for user " + userId);
        }

        // 组装 DTO
        InitKeyRespDTO respDTO = new InitKeyRespDTO();

        // IdentityKeyDTO
        InitKeyRespDTO.IdentityKeyDTO identityKeyDTO = new InitKeyRespDTO.IdentityKeyDTO();
        BeanUtils.copyProperties(identityKeyDO, identityKeyDTO);
        identityKeyDTO.setId(identityKeyDO.getKeyId());

        respDTO.setIdentityKey(identityKeyDTO);

        // SignedPreKeyDTO
        InitKeyRespDTO.SignedPreKeyDTO signedPreKeyDTO = new InitKeyRespDTO.SignedPreKeyDTO();
        BeanUtils.copyProperties(signedPreKeyDO, signedPreKeyDTO);
        signedPreKeyDTO.setId(signedPreKeyDO.getKeyId());
        respDTO.setSignedPreKey(signedPreKeyDTO);

        // PreKeyDTO 列表
        List<InitKeyRespDTO.PreKeyDTO> preKeyDTOs = preKeyDOS.stream().map(entity -> {
            InitKeyRespDTO.PreKeyDTO dto = new InitKeyRespDTO.PreKeyDTO();
            dto.setId(entity.getKeyId());
            dto.setPublicKey(entity.getPublicKey());
            dto.setCipher(entity.getCipher());
            dto.setSalt(entity.getSalt());
            return dto;
        }).collect(Collectors.toList());
        respDTO.setPreKeys(preKeyDTOs);

        // 设置密码哈希等字段
        respDTO.setPasswordHash(initKeyDO.getPasswordHash());
        respDTO.setPasswordSalt(initKeyDO.getPasswordSalt());
        respDTO.setOneTimeId(initKeyDO.getOneTimeId());
        respDTO.setLocalId(initKeyDO.getLocalId());

        return respDTO;
    }

    @Override
    public PreKeyBundleRespDTO fetchPreKeyBundle(FetchPreKeyReqDTO req) {
        String userId = req.getUserId();
        Boolean isSession = req.getIsSession();
        IdentityKeyDO identityKeyDO = identityKeyService.selectIdentityKeyByUserId(userId);
        SignedPreKeyDO signedPreKeyDO = signedPreKeyService.selectSignedPreKeyByUserId(userId);
        PreKeyDO preKey = preKeyService.selectPreKeyByUserId(userId);
        InitKeyDO initKeyDO = initKeyService.selectInitKeyByUserId(userId);
        if (identityKeyDO == null || signedPreKeyDO == null || preKey == null | initKeyDO == null) {
            throw new RuntimeException("用户不存在");
        }
        PreKeyBundleRespDTO preKeyBundleRespDTO = PreKeyBundleRespDTO.builder()
                .signedPreKey(signedPreKeyDO.getPublicKey())
                .signedPreKeyId(signedPreKeyDO.getKeyId())
                .identityKey(identityKeyDO.getPublicKey())
                .identityKeyId(identityKeyDO.getKeyId())
                .localId(initKeyDO.getLocalId())
                .oneTimeId(initKeyDO.getOneTimeId())
                .userId(userId)
                .signature(signedPreKeyDO.getSignature())
                .build();
        preKeyBundleRespDTO.setPreKey(preKey.getPublicKey());
        preKeyBundleRespDTO.setPreKeyId(preKey.getKeyId());
        if(!isSession) {
            preKeyService.deletePreKey(preKey);
        } else {
            preKeyService.setPreKeyUser(preKey);
        }

        return preKeyBundleRespDTO;
    }

    @Override
    public void storeEncryptionSenderKey(EncryptionSenderKeyReqDTO request) {
        encryptionSenderKeyService.storeEncryptionSenderKey(request);
    }

    @Override
    public Integer getIdentityKeyIdByUserId(IdentityKeyIdByUserIdReqDTO request) {
        return identityKeyService.selectIdentityKeyByUserId(request.getUserId()).getKeyId();
    }

    @Override
    public Boolean hasDecryptionSenderKey(HasDecryptionSenderKeyReqDTO request) {
        return decryptionSenderKeyService.hasDecryptionSenderKey(request);
    }

    @Override
    public GetDecryptionSenderKeyRespDTO getDecryptionSenderKey(getDecryptionSenderKeyReqDTO request) {
        return decryptionSenderKeyService.getDecryptionSenderKey(request);
    }

    @Override
    public void storeDecryptionSenderKey(StoreDecryptionSenderKeyReqDTO request) {
        decryptionSenderKeyService.storeDecryptionSenderKey(request);
    }
}
